package com.heima.article.service.impl;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.aliyun.oss.AliyunOssTemplate;
import com.heima.api.dto.ArticleDto;
import com.heima.article.mapper.ApArticleConfigMapper;
import com.heima.article.mapper.ApArticleContentMapper;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.ApArticleService;
import com.heima.common.contants.ArticleContants;
import com.heima.common.contants.MessageConstants;
import com.heima.model.aritlce.dto.ArticleHomeDto;
import com.heima.model.aritlce.pojo.ApArticle;
import com.heima.model.aritlce.pojo.ApArticleConfig;
import com.heima.model.aritlce.pojo.ApArticleContent;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import java.util.*;
import java.util.stream.Collectors;

@Service("apArticleService")
public class ApArticleServiceImpl extends ServiceImpl<ApArticleMapper, ApArticle> implements ApArticleService {

    @Resource
    private ApArticleMapper apArticleMapper;

    @Resource
    private ApArticleContentMapper apArticleContentMapper;

    @Resource
    private ApArticleConfigMapper apArticleConfigMapper;

    @Autowired
    private Configuration configuration;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private AliyunOssTemplate aliyunOssTemplate;

    @Override
    public void saveArticle(ArticleDto dto){
        //1. 判断是新增操作还是修改操作  newsId
        ApArticle apArticle = apArticleMapper.selectOne(Wrappers.<ApArticle>lambdaQuery().eq(ApArticle::getNewsId, dto.getNewsId()));
        if (apArticle == null) {
            //3. 如果是新增 , 保存数据到数据库
            //3.1 保存文章基本信息到数据库  ap_article
            apArticle = new ApArticle();
            BeanUtils.copyProperties(dto, apArticle);
            apArticle.setLikes(0);
            apArticle.setCollection(0);
            apArticle.setViews(0);
            apArticle.setComment(0);
            apArticle.setCreatedTime(new Date());
            apArticle.setUpdatedTime(new Date());

            //3.2 保存文章配置信息到数据库  ap_article_config
            ApArticleConfig apArticleConfig = new ApArticleConfig();
            apArticleConfig.setArticleId(apArticle.getId());
            apArticleConfig.setEnable(1);
            apArticleConfig.setIsDelete(0);
            apArticleConfig.setIsComment(1);
            apArticleConfig.setIsForward(1);
            apArticleConfig.setCreatedTime(new Date());
            apArticleConfig.setUpdatedTime(new Date());
            apArticleConfigMapper.insert(apArticleConfig);

            //3.1 保存文章内容信息到数据库  ap_article_content
            ApArticleContent apArticleContent = new ApArticleContent();
            apArticleContent.setEnable(1);
            apArticleContent.setArticleId(apArticle.getId());
            apArticleContent.setContent(dto.getContent());
            apArticleContent.setCreatedTime(new Date());
            apArticleContent.setUpdatedTime(new Date());
            apArticleContentMapper.insert(apArticleContent);
            // 封装远程调用数据、创建搜索索引
            sendResultMessage(apArticle,apArticleContent);
            try {
                String url = StaticPageGeneration(apArticle, apArticleContent);
                if (url != null){
                    apArticle.setStaticUrl(url);
                }
                apArticleMapper.insert(apArticle);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            //4. 如果是修改 , 更新数据到数据库
            //4.1 修改文章基本信息  ap_article
            Long articleId = apArticle.getId();
            BeanUtils.copyProperties(dto, apArticle);
            apArticle.setId(articleId);
            apArticle.setUpdatedTime(new Date());
            apArticleMapper.updateById(apArticle);

            //4.2 修改文章内容信息 ap_article_content
            ApArticleContent apArticleContent = apArticleContentMapper.selectById(articleId);
            apArticleContent.setContent(dto.getContent());
            apArticleContent.setUpdatedTime(new Date());
            apArticleContentMapper.updateById(apArticleContent);
        }
    }

    /**
     * 发送消息
     * @param apArticle
     * @param apArticleContent
     * @return void
     */
    private void sendResultMessage(ApArticle apArticle,ApArticleContent apArticleContent) {
        // 封装远程调用数据、远程调用创建索引
        HashMap<String, Object> data = new HashMap<>();
        // "id"
        data.put("id",apArticle.getId());
        // "publishTime"
        data.put("publishTime",apArticle.getPublishTime());
        // "layout"
        data.put("layout",apArticle.getLayout());
        // "images"
        data.put("images",apArticle.getImages());
        // "staticUrl"
        data.put("staticUrl",apArticle.getStaticUrl());
        // "authorId"
        data.put("authorId",apArticle.getAuthorId());
        // "authorName"
        data.put("authorName",apArticle.getAuthorName());
        // "title"
        data.put("title",apArticle.getTitle());
        // "content"
        data.put("content",apArticleContent.getContent());
        // "suggestion"
        JSONArray objects = JSONUtil.parseArray(apArticleContent.getContent());
        ArrayList<String> suggestion = new ArrayList<>();
        objects.forEach(o ->
                suggestion.add(JSONUtil.toBean(o.toString(), Map.class).get("value").toString()));
        suggestion.add(apArticle.getTitle());
        data.put("suggestion",suggestion);

        // 发送消息
        rabbitTemplate.convertAndSend(MessageConstants.SEARCH_EXCHANGE,MessageConstants.SEARCH_KEY, JSONUtil.toJsonStr(data));
    }

    /***
     * 生成静态页
     * @return
     */
    public String StaticPageGeneration(ApArticle apArticle, ApArticleContent apArticleContent) throws Exception {
        //1. 加载模板
        Template template = configuration.getTemplate("article.ftl");

        //2. 封装数据模型（从数据库实体中提取字段）
        Map<String, Object> dataMap = new HashMap<>();

        //2.1 文章基本信息
        dataMap.put("title", apArticle.getTitle());
        dataMap.put("authorName", apArticle.getAuthorName());
        dataMap.put("publishTime", apArticle.getPublishTime().getTime()); // 时间戳（毫秒）

        //2.2 文章内容（假设 content 是 JSON 字符串，解析为 List<Map>）
        List<Map<String, Object>> contentList = new ArrayList<>();
        // 示例解析逻辑（需根据实际数据结构调整）
//        String contentJson = apArticleContent.getContent();
        // 此处使用 FastJSON 解析（需引入依赖）
        // List<Map> contentItems = JSON.parseArray(contentJson, Map.class);
        // 暂用模拟数据代替
        Map<String, Object> textItem = new HashMap<>();
        textItem.put("type", "text");
        // 文章内容中提取文本内容
        String content = JSONUtil.parseArray(apArticleContent.getContent()).toList(Map.class).stream()
                // 过滤type=text的文本内容
                .filter(map -> map.get("type").equals("text"))
                // 获取value文本内容
                .map(map -> map.get("value").toString())
                // 用逗号拼接
                .collect(Collectors.joining(","));
        textItem.put("value", content);
        contentList.add(textItem);

        Map<String, Object> imageItem = new HashMap<>();
        imageItem.put("type", "image");
        imageItem.put("value", apArticle.getImages());
        contentList.add(imageItem);

        dataMap.put("content", contentList);

        //2.3 用户关系状态（模拟默认值）
        Map<String, Object> relation = new HashMap<>();
        relation.put("isfollow", false);   // 是否关注
        relation.put("islike", false);     // 是否点赞
        relation.put("isunlike", false);   // 是否不喜欢
        relation.put("iscollection", false); // 是否收藏
        dataMap.put("relation", relation);

        //2.4 评论数据（模拟数据，需根据业务补充）
        List<Map<String, Object>> comments = new ArrayList<>();
        Map<String, Object> comment = new HashMap<>();
        comment.put("authorName", "用户A");
        comment.put("content", "这篇文章写得不错！");
        comment.put("createdTime", System.currentTimeMillis());
        comment.put("likes", 10);
        comment.put("reply", 2);
        comments.add(comment);
        dataMap.put("comments", comments);

        //3. 填充模板并输出到文件
        StringWriter writer = new StringWriter();
        template.process(dataMap, writer);
        //4 将静态HTML页面上传到aliyun
        ByteArrayInputStream is = new ByteArrayInputStream(writer.toString().getBytes());
        return aliyunOssTemplate.upload(apArticle.getId()+".html", is);
    }

    @Override
    public List<ApArticle> load(ArticleHomeDto dto, short loadType) {
        //1. 校验参数
        //1.1 频道参数处理
        String tag = StringUtils.isEmpty(dto.getTag()) ? ArticleContants.DEFAULT_TAG : dto.getTag();
        //1.2 每页展示数据条数参数处理
        Integer size = dto.getSize() == null ? 10 : dto.getSize();
        size = Math.min(size, 50);
        //1.3 最小时间参数处理
        Date minTime = dto.getMinBehotTime() == null ? new Date() : dto.getMinBehotTime();
        //1.4 最大时间参数处理
        Date maxTime = dto.getMaxBehotTime() == null ? new Date() : dto.getMaxBehotTime();
        //2. 封装查询条件
        Map<String, Object> queryParams = new HashMap<>(5);
        queryParams.put("tag", tag);
        queryParams.put("size", size);
        queryParams.put("minTime", minTime);
        queryParams.put("maxTime", maxTime);
        queryParams.put("loadType", loadType);

        //3. 调用数据访问层完成查询
        List<ApArticle> articleList = apArticleMapper.queryByParams(queryParams);

        //4. 封装数据返回
        return articleList;
    }

    /**
     * 修改文章上下架
     * @param dto
     * @return
     */
    @Override
    public void updateArticle(ArticleDto dto) {
        // 1、修改文章基础信息表
        apArticleMapper.update(null,Wrappers.<ApArticle>lambdaUpdate().eq(ApArticle::getId,dto.getId()).set(ApArticle::getEnable, dto.getEnable()));
        // 2、修改文章配置表
        apArticleConfigMapper.update(null,Wrappers.<ApArticleConfig>lambdaUpdate().eq(ApArticleConfig::getArticleId,dto.getId()).set(ApArticleConfig::getEnable, dto.getEnable()));
        // 3、修改文章内容信息表
        apArticleContentMapper.update(null,Wrappers.<ApArticleContent>lambdaUpdate().eq(ApArticleContent::getArticleId,dto.getId()).set(ApArticleContent::getEnable, dto.getEnable()));
    }
}

